/**
 ****************************************************************************************************
 * @file        lwip_demo
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.0
 * @date        2020-08-01
 * @brief       lwIP SOCKET TCPClient 实验
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 阿波罗 F429开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 ****************************************************************************************************
 */

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include <stdint.h>
#include <stdio.h>
#include <lwip/sockets.h>
// #include "./BSP/LCD/lcd.h"
#include "./MALLOC/malloc.h"
#include "lwip/opt.h"
#include "lwip/sys.h"
#include "lwip/api.h"
#include "lwip_demo.h"


/* 设置远程IP地址 */
// #define DEST_IP_ADDR0               192
// #define DEST_IP_ADDR1               168
// #define DEST_IP_ADDR2                 1
// #define DEST_IP_ADDR3               167

/* 需要自己设置远程IP地址 */
#define IP_ADDR               "192.168.1.111"

#define LWIP_DEMO_RX_BUFSIZE  100                    /* 最大接收数据长度 */
#define LWIP_DEMO_PORT        8080                   /* 连接的本地端口号 */
#define LWIP_SEND_THREAD_PRIO (tskIDLE_PRIORITY + 3) /* 发送数据线程优先级 */
/* 接收数据缓冲区 */
uint8_t g_lwip_demo_recvbuf[LWIP_DEMO_RX_BUFSIZE];

/* 发送数据内容 */
uint8_t g_lwip_demo_sendbuf[] = "ALIENTEK DATA \r\n";
/* 数据发送标志位 */
uint8_t g_lwip_send_flag;
int g_lwip_sock          = -1;
int g_lwip_connect_state = 0;
static void lwip_send_thread(void *arg);

extern QueueHandle_t g_display_queue; /* 显示消息队列句柄 */

// /**
//  * @brief       发送数据线程
//  * @param       无
//  * @retval      无
//  */
// void lwip_data_send(void)
// {
//     sys_thread_new(
//         "lwip_send_thread", lwip_send_thread, NULL, 512, LWIP_SEND_THREAD_PRIO);
// }

/**
 * @brief       lwip_demo实验入口
 * @param       无
 * @retval      无
 */

void lwip_demo3(void)
{
    struct sockaddr_in atk_client_addr;
    err_t err;
    int recv_data_len;
    BaseType_t lwip_err;
    char *tbuf = NULL;

    printf(">> [debug] this is lwip_demo\r\n");

    /* 创建发送数据线程 */
    sys_thread_new("lwip_send_thread", lwip_send_thread, NULL, 512, LWIP_SEND_THREAD_PRIO);

    while (1) {
    sock_start:
        g_lwip_connect_state = 0;

        // 清理之前的资源
        if (tbuf != NULL) {
            myfree(SRAMIN, tbuf);
            tbuf = NULL;
        }
        if (g_lwip_sock >= 0) {
            closesocket(g_lwip_sock);
            g_lwip_sock = -1;
            vTaskDelay(100); // 给协议栈时间清理
        }

        // 配置服务器地址
        atk_client_addr.sin_family      = AF_INET;               /* 表示IPv4网络协议 */
        atk_client_addr.sin_port        = htons(LWIP_DEMO_PORT); /* 端口号 */
        atk_client_addr.sin_addr.s_addr = inet_addr(IP_ADDR);    /* 远程IP地址 */
        memset(&(atk_client_addr.sin_zero), 0, sizeof(atk_client_addr.sin_zero));

        // 创建socket
        g_lwip_sock = socket(AF_INET, SOCK_STREAM, 0);    // 可靠数据流交付服务既是TCP协议
        if (g_lwip_sock < 0) {
            printf("Socket create failed!\r\n");
            vTaskDelay(1000);
            goto sock_start;
        }

        // 设置socket选项 - 增加稳定性
        struct timeval timeout;
        timeout.tv_sec = 3;  // 3秒超时
        timeout.tv_usec = 0;
        setsockopt(g_lwip_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
        
        int keepalive = 1;
        setsockopt(g_lwip_sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive));

        tbuf = mymalloc(SRAMIN, 200); /* 申请内存 */
        if (tbuf == NULL) {
            printf("Memory alloc failed!\r\n");
            closesocket(g_lwip_sock);
            vTaskDelay(1000);
            goto sock_start;
        }
        sprintf((char *)tbuf, "Client Port:%d\r\n", LWIP_DEMO_PORT); /* 客户端端口号 */
        printf((char *)tbuf);

        printf("Socket try to connect remote ip...\r\n");
        /* 连接远程IP地址 */
        err = connect(g_lwip_sock, (struct sockaddr *)&atk_client_addr, sizeof(struct sockaddr));

        if (err == -1 ) {
            printf("Connect remote IP Fail, errno: %d\r\n", errno);
            closesocket(g_lwip_sock);    // 先关闭socket
            g_lwip_sock = -1;            // 再标记为无效
            myfree(SRAMIN, tbuf);        // 立即释放，避免内存泄漏
            vTaskDelay(1000);    // 延长重连间隔
            goto sock_start;
        }

        printf("State:Connection Successful \r\n");
        g_lwip_connect_state = 1;
        printf(">>> position1 \r\n");

        // 连接成功后立即发送识别消息
        const char *identify_msg = "STM32 Client Connected\r\n";
        send(g_lwip_sock, identify_msg, strlen(identify_msg), 0);
        printf("Identification message sent\r\n");

        // 使用select的非阻塞接收循环（方案3的核心改进）
        while (1) {
            fd_set readfds;
            struct timeval select_timeout;
            int select_ret;
            
            FD_ZERO(&readfds);
            FD_SET(g_lwip_sock, &readfds);
            select_timeout.tv_sec = 2;  // 2秒超时
            select_timeout.tv_usec = 0;
            
            printf("Waiting for data (select)...\r\n");
            select_ret = select(g_lwip_sock + 1, &readfds, NULL, NULL, &select_timeout);
            
            if (select_ret > 0) {
                if (FD_ISSET(g_lwip_sock, &readfds)) {
                    // 有数据可读
                    memset(g_lwip_demo_recvbuf, 0, LWIP_DEMO_RX_BUFSIZE);
                    
                    recv_data_len = recv(g_lwip_sock, g_lwip_demo_recvbuf, LWIP_DEMO_RX_BUFSIZE, 0);
                    sprintf((char *)tbuf, "Socket receive data length: %d\r\n", recv_data_len);
                    printf((char *)tbuf);
                    
                    if (recv_data_len > 0) {
                        printf(">>> Received valid data: %d bytes\r\n", recv_data_len);
                        
                        // 处理接收到的数据
                        g_lwip_demo_recvbuf[recv_data_len] = '\0'; // 确保字符串终止
                        printf("Data: %s\r\n", g_lwip_demo_recvbuf);
                        
                        // 发送到显示队列
                        lwip_err = xQueueSend(g_display_queue, &g_lwip_demo_recvbuf, 0);
                        if (lwip_err == errQUEUE_FULL) {
                            printf("Key_Queue is full, data send Fail! \r\n");
                        }
                        
                        // 可选：发送ACK回复
                        char ack_msg[32];
                        snprintf(ack_msg, sizeof(ack_msg), "ACK:%d", recv_data_len);
                        send(g_lwip_sock, ack_msg, strlen(ack_msg), 0);
                        
                    } else if (recv_data_len == 0) {
                        printf("Connection closed by peer\r\n");
                        break;
                    } else {
                        // recv错误
                        if (errno == EWOULDBLOCK || errno == EAGAIN) {
                            printf("No data available (non-blocking)\r\n");
                        } else {
                            printf("Recv error: %d\r\n", errno);
                            break;
                        }
                    }
                }
            } else if (select_ret == 0) {
                // 超时，发送保持活跃的消息
                // printf("Select timeout, sending keepalive...\r\n");
                // send(g_lwip_sock, "ALIVE", 5, 0);
            } else {
                // select错误
                printf("Select error: %d\r\n", errno);
                break;
            }
            
            vTaskDelay(100); // 给其他任务运行的机会
        }

        // 连接断开后的清理
        printf("State:Disconnect, reconnecting...\r\n");
        closesocket(g_lwip_sock);
        g_lwip_sock = -1;
        g_lwip_connect_state = 0;
        myfree(SRAMIN, tbuf);
        tbuf = NULL;
        vTaskDelay(2000); // 重连前等待2秒
    }
}


void lwip_demo(void)
{
    struct sockaddr_in atk_client_addr;
    err_t err;
    int recv_data_len;
    BaseType_t lwip_err;
    char *tbuf;

    printf(">> [debug] this is lwip_demo\r\n");

    /* 创建发送数据线程 */
    // lwip_data_send();
    sys_thread_new("lwip_send_thread", lwip_send_thread, NULL, 512, LWIP_SEND_THREAD_PRIO);


    while (1) {
    sock_start:
        g_lwip_connect_state = 0;

        // 配置服务器地址
        atk_client_addr.sin_family      = AF_INET;               /* 表示IPv4网络协议 */
        atk_client_addr.sin_port        = htons(LWIP_DEMO_PORT); /* 端口号 */
        atk_client_addr.sin_addr.s_addr = inet_addr(IP_ADDR);    /* 远程IP地址 */

        // 创建socket
        g_lwip_sock = socket(AF_INET, SOCK_STREAM, 0);    // 可靠数据流交付服务既是TCP协议
        if (g_lwip_sock < 0) {
            printf("Socket create failed!\r\n");
            vTaskDelay(1000);
            goto sock_start;
        }
        memset(&(atk_client_addr.sin_zero), 0, sizeof(atk_client_addr.sin_zero));


        tbuf = mymalloc(SRAMIN, 200); /* 申请内存 */
        if (tbuf == NULL) {
            printf("Memory alloc failed!\r\n");
            closesocket(g_lwip_sock);
            vTaskDelay(1000);
            goto sock_start;
        }
        sprintf((char *)tbuf, "Client Port:%d\r\n", LWIP_DEMO_PORT); /* 客户端端口号 */
        printf((char *)tbuf);
        // myfree(SRAMIN, tbuf);    // 立即释放，避免内存泄漏

        printf("Socket try to connect remote ip...\r\n");
        /* 连接远程IP地址 */
        err = connect(g_lwip_sock, (struct sockaddr *)&atk_client_addr, sizeof(struct sockaddr));

        if (err == -1 ) {
            printf("Connect remote IP Fail\r\n");
            closesocket(g_lwip_sock);    // 先关闭socket
            g_lwip_sock = -1;            // 再标记为无效
            myfree(SRAMIN, tbuf);        // 立即释放，避免内存泄漏

            vTaskDelay(100);    // 延长重连间隔
            goto sock_start;
        }
        printf("State:Connection Successful \r\n");
        g_lwip_connect_state = 1;

        while (1) {

            memset(g_lwip_demo_recvbuf, 0, LWIP_DEMO_RX_BUFSIZE);

            recv_data_len = recv(g_lwip_sock, g_lwip_demo_recvbuf, LWIP_DEMO_RX_BUFSIZE, 0);
            // sprintf((char *)tbuf, "Socket receive data length: %d\r\n", recv_data_len);
            // printf((char *)tbuf);
            // printf((char *)g_lwip_demo_recvbuf);

            // // 然后修改接收循环中的判断：
            // if (recv_data_len > 0) {
            //     printf(">>>Socket receive data length valid %d\r\n");
            // }
            // else if (recv_data_len < 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) {
            //     // 没有数据，正常继续
            //     printf(">>>Socket receive data <0\r\n");

            //     vTaskDelay(100);
            //     continue;
            // }
            // else {
            //     // 真正的错误
            //     break;
            // }
            if (recv_data_len <= 0) {
                closesocket(g_lwip_sock);
                g_lwip_sock          = -1;
                g_lwip_connect_state = 0;    // 重要：通知发送线程连接已断开

                printf("State:Disconnect\r\n");
                myfree(SRAMIN, tbuf);
                goto sock_start;
            }
            /* 接收的数据 */
            lwip_err = xQueueSend(g_display_queue, &g_lwip_demo_recvbuf, 0);

            if (lwip_err == errQUEUE_FULL) {
                printf("Key_Queue is full, data send Fail! \r\n");
            }

            vTaskDelay(100);
        }
    }


}



/**
 * @brief       发送数据线程函数
 * @param       pvParameters : 传入参数(未用到)
 * @retval      无
 */
void lwip_send_thread(void *pvParameters)
{
    pvParameters = pvParameters;

    err_t err;

    while (1) {
        while (1) {
            if (((g_lwip_send_flag & LWIP_SEND_DATA) == LWIP_SEND_DATA) &&
                (g_lwip_connect_state == 1)) /* 有数据要发送 */
            {
                err = write(g_lwip_sock, g_lwip_demo_sendbuf, sizeof(g_lwip_demo_sendbuf));

                if (err < 0) {
                    break;
                }

                g_lwip_send_flag &= ~LWIP_SEND_DATA;
            }

            vTaskDelay(10);
        }

        closesocket(g_lwip_sock);
    }

    while (1) {
        /* 等待连接建立 */
        if (g_lwip_connect_state == 1 && g_lwip_sock >= 0) {
            if ((g_lwip_send_flag & LWIP_SEND_DATA) == LWIP_SEND_DATA) {
                err = write(g_lwip_sock, g_lwip_demo_sendbuf, sizeof(g_lwip_demo_sendbuf));

                if (err < 0) {
                    printf("Send failed, closing socket\r\n");
                    closesocket(g_lwip_sock);
                    g_lwip_sock          = -1;
                    g_lwip_connect_state = 0;
                }
                else {
                    g_lwip_send_flag &= ~LWIP_SEND_DATA;
                    printf("Send data successful\r\n");
                }
            }
        }

        vTaskDelay(50); /* 适当延长延时 */
    }
}
